package com.dage.salesflow.service;

import cn.dev33.satoken.stp.StpUtil;
import com.dage.salesflow.constant.SysConstant;
import com.dage.salesflow.kit.Ret;
import com.dage.salesflow.kit.TreeKit;
import com.dage.salesflow.model.Area;
import com.dage.salesflow.model.User;
import com.dage.salesflow.model.vo.TreeNode;
import com.dage.salesflow.validation.DelForeignInfo;
import com.dage.salesflow.validation.ValidationKit;
import com.jfinal.aop.Inject;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import io.jboot.aop.annotation.Bean;
import io.jboot.aop.annotation.Transactional;
import io.jboot.components.cache.annotation.CacheEvict;
import io.jboot.components.cache.annotation.Cacheable;
import io.jboot.db.model.Columns;
import io.jboot.service.JbootServiceBase;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Bean
public class AreaService extends JbootServiceBase<Area> {

	@Inject
	UserService userService;

	/**
	 * 树形列表
	 *
	 * @return
	 */
	public List list(String name) {
		String sql = "SELECT id,pid,`name`,code,sort,note FROM `t_area` WHERE 1=1";
		List<Object> paras = new ArrayList<>();
		if (StrKit.notBlank(name)) {
			sql += " AND `name` like ?";
			paras.add("%" + name + "%");
		}
		sql += " ORDER BY sort ASC";
		return TreeKit.appendParentNodes(DAO.find(sql, paras.toArray()));
	}

	/**
	 * 递归获取全量树形列表
	 *
	 * @param pid 父级id
	 */
	public List<TreeNode> listTree(int pid) {
		String sql = "SELECT id,pid,`name`,`code` FROM `t_area` WHERE pid=? AND `code` LIKE ? ORDER BY sort ASC";
		User user = userService.getById(StpUtil.getLoginIdAsInt());
		Area area = getById(user.getAreaId());
		List<TreeNode> nodes = area2TreeNode(DAO.find(sql, pid, area.getCode() + "%"));
		for (TreeNode node : nodes) {
			node.setChildren(listTree(node.getId()));
		}
		return nodes;
	}

	private List<TreeNode> area2TreeNode(List<Area> areas) {
		List<TreeNode> nodes = new ArrayList<>();
		for (Area area : areas) {
			nodes.add(new TreeNode(area.getCode(), area.getId(), area.getName()));
		}
		return nodes;
	}

	/**
	 * 分页
	 *
	 * @param name 区域名称
	 * @return
	 */
	public Page<Area> listByPage(String name, int pageNum, int pageSize) {
		String select = "SELECT id,`name`,note";
		String sql = "FROM `t_area` WHERE 1=1";
		List<Object> paras = new ArrayList<>();
		if (StrKit.notBlank(name)) {
			sql += " AND `name` like ?";
			paras.add("%" + name + "%");
		}
		User user = userService.getById(StpUtil.getLoginIdAsInt());
		Area area = getById(user.getAreaId());
		sql += " AND  `code` LIKE ?";
		paras.add(area.getCode() + "%");
		sql += " ORDER BY sort ASC";
		return DAO.paginate(pageNum, pageSize, select, sql, paras.toArray());
	}

	/**
	 * 添加
	 */
	@Transactional
	public Ret add(Area node) {
		if (findCountByColumns(Columns.create("name", node.getName())) > 0) {
			return Ret.err("名称不能重复");
		}
		Area n = findById(node.getPid());
		String code = "";
		if (n != null) {
			code = n.getCode();
		}
		if (save(node) != null) {
			node.setCode(code + String.format("%0" + Area.CODE_LEN + "d", node.getId()));
			node.update();
			return Ret.ok();
		} else {
			return Ret.err("添加失败");
		}
	}

	@Cacheable(name = SysConstant.CACHE_AREA, key = "#(id)")
	public Area getById(Integer id) {
		return findById(id);
	}

	/**
	 * 修改
	 *
	 * @param area
	 * @return
	 */
	@CacheEvict(name = SysConstant.CACHE_AREA, key = "#(area.id)")
	public Ret edit(Area area) {
		if (findCountByColumns(
				Columns.create("name", area.getName())
						.add(Columns.create().ne("id", area.getId()))
		) > 0) {
			return Ret.err("名称不能重复");
		}
		if (update(area)) {
			return Ret.ok();
		} else {
			return Ret.err("修改失败");
		}
	}

	/**
	 * 删除
	 */
	@CacheEvict(name = SysConstant.CACHE_AREA, key = "#(id)")
	public Ret del(Area area) {
		List<Area> childNodes = TreeKit.getChildNodes(area.getId(), area);
		Set<DelForeignInfo> delForeignInfo = ValidationKit.getDelForeignInfo(Area.class);
		Ret ret = checkDel(area, delForeignInfo);
		if (!ret.isOk()) {
			return ret;
		}
		for (Area childNode : childNodes) {
			ret = checkDel(childNode, delForeignInfo);
			if (!ret.isOk()) {
				return ret;
			}
		}
		if (deleteById(area.getId())) {
			return Ret.ok();
		} else {
			return Ret.err("删除失败");
		}
	}

	private Ret checkDel(Area area, Set<DelForeignInfo> delForeignInfo) {
		if (StrKit.isBlank(area.getName())) {
			area.setName("");
		}
		for (DelForeignInfo info : delForeignInfo) {
			long num = Db.queryLong(info.sql, area.getId());
			if (num > 0) {
				return Ret.err(area.getName() + "有" + num + "条关联的" + info.name + "数据，删除失败！");
			}
		}
		return Ret.ok();
	}

	/**
	 * 校验区域级别
	 *
	 * @param level 1级大区，2级省份。。。
	 */
	public boolean checkLevel(int id, int level) {
		Area area = getById(id);
		return area.getCode().length() == (level + 1) * Area.CODE_LEN;
	}

	/**
	 * 校验区域是否为叶子节点
	 */
	public boolean checkLeaf(int id) {
		return Db.queryLong("SELECT COUNT(*) FROM `t_area` WHERE pid=?", id) <= 0;
	}

	/**
	 * 获取指定级别的父节点
	 *
	 * @param id
	 * @param level 1级大区，2级省份。。。
	 */
	public Area getParentNode(int id, int level) {
		Area area = getById(id);
		if (area.getCode().length() < (level + 1) * Area.CODE_LEN) {
			return null;
		}
		if (area.getCode().length() == (level + 1) * Area.CODE_LEN) {
			return area;
		}
		String code = area.getCode().substring(0, (level + 1) * Area.CODE_LEN);
		return findFirstByColumns(Columns.create("code", code));
	}
}